home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
packet
/
p_tapr
/
tnchst
/
mthdrive.asm
< prev
next >
Wrap
Assembly Source File
|
1992-03-16
|
19KB
|
975 lines
PAGE 60,132
TITLE MTDRIVER
;
; MTHDRIVER
;
; Derived from AA4RE's COMBIOS.ASM, heavily modifed by
; WA7MXZ, WA7MBL, W0RLI, and N2WX
;
;
;
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS: _TEXT
ASSUME DS: nothing
ASSUME ES: nothing
ASSUME SS: nothing
; Program _COM_START and buffer declares
ORG 0
; Area where things are declared
include MTCONST.ASM
COMPORT EQU 0
dummy: ; Dummy labels to provide a structure
i_buf DB buffer_size dup(?) ; Buffer (1 per com card)
i_buf_e: ; End of buffer
comnumber DB ? ; Comm number - 1
flags DB ? ; Flag byte
last_rs DB ? ; Last receive status
hiv DB ? ; Hardware interrupt vector
int_mask DB ? ; Mask for 8259
baseaddr DW ? ; Base port address
i_count DW ? ; # of chars in buffer
i_buf_in DW ? ; Buffer in pointer
i_buf_out DW ? ; Buffer out pointer
dummy_end:
ORG dummy ; Back up over this
; These are the things to work with
IF COMPORT - 1 ; COM1 defined below
DB buffer_size dup(?) ; Buffer (1 per com card)
DB 0 ; Com number
DB 0 ; Flags
DB 0 ; Last receive status
DB 0CH ; Hardware interrupt vector
DB 0EFH ; Mask
DW 03F8H ; Base port address
DW 0 ; # of chars in buffer
DW ? ; Buffer in pointer
DW ? ; Buffer out pointer
ELSE ; else COM2
DB buffer_size dup(?) ; Buffer (1 per com card)
DB 1 ; Com number
DB 0 ; Flags
DB 0 ; Last receive status
DB 0bH ; Hardware interrupt vector
DB 0F7H ; Mask
DW 02F8H ; Base port address
DW 0 ; # of chars in buffer
DW ? ; Buffer in pointer
DW ? ; Buffer out pointer
ENDIF
comend: ; Marker for last com port
; Static variables
old_bios_vector DW ? ; Save previous interrupt vector
DW ?
old_hdwr_vec DW ?
DW ?
old_ier DB ?
old_pic_msk DB ?
divisor_table LABEL WORD
DW 1047 ; 110
DW 6 ; 19200
DW 384 ; 300
DW 192 ; 600
DW 96 ; 1200
DW 48 ; 2400
DW 24 ; 4800
DW 12 ; 9600
; Our BIOS handler
rsint:
ASSUME DS: NOTHING ; Don't use DS
ASSUME ES: NOTHING ; Don't use ES
ASSUME SS: NOTHING ; Don't use SS
; Not disabled please
STI
; See if this is our vector?
PUSH BP ; Save BP over our loop
XOR BP,BP
CMP DL,CS:comnumber[BP] ; Is this our port?
JE rsint_ours ; Yes...
; Not us.. Pop things out and call regular handler
POP BP ; Pop BP
JMP CS:DWORD PTR old_bios_vector
; BP now contains the pointer to the com block... See what
; the user has requested and we may or may not do it.......
rsint_ours:
PUSH DX ; We need the DX register
PUSH CX ; We need the CX register
PUSH BX ; We need the BX register
MOV CX,baseaddr[BP] ; Get base address for chip
OR AH,AH ; Initialize
JE rsint_init ; Yes...
DEC AH ; 1 = Send character
JZ rsint_send
DEC AH ; 2 = Receive character
JZ rsint_recv_jmp
DEC AH ; 3 = Status request
JZ rsint_status_jmp
DEC AH ; 4 = Inquiry
JZ rsint_inquiry_jmp
jmp rsint_exit ; Nope..
rsint_recv_jmp:
JMP rsint_recv
rsint_status_jmp:
JMP rsint_status
rsint_inquiry_jmp:
JMP rsint_inquiry
; Interrupt exit
rsint_exit:
POP BX ; Restore registers
POP CX
POP DX
POP BP
IRET ; and leave
; Init..
rsint_init:
MOV AH,AL ; Save the parms for later
MOV BL,AH ; Look up the baud rate
MOV CL,4 ; parameter
ROL BL,CL
AND BX,0EH
MOV BX,divisor_table[BX]
MOV CX,baseaddr[BP] ; Get base address for chip
MOV DX,CX ; Address of LCR
ADD DX,lcr_8250
MOV AL,10000000B ; Enable access to divisor
OUT DX,AL
MOV DX,CX ; Address of lower divisior half
ADD DX,dll_8250
MOV AL,BL ; Put lower half
OUT DX,AL
MOV DX,CX ; Address of upper divisior half
ADD DX,dlm_8250
MOV AL,BH ; Put upper half
OUT DX,AL
MOV AL,AH ; Get parms back
AND AL,01FH ; Throw away baud rate
MOV DX,CX ; Address of LCR
ADD DX,lcr_8250
OUT DX,AL ; Output the parms
; Turn on the port
MOV DX,CX ; Compute port address for the MCR
ADD DX,mcr_8250
mov AL,00001011B ; Raise DTR, RTS & OUT2
out dx,al ; OUT2 turns on interrupts
JMP rsint_status ; Now just status please
; Send a character
rsint_send:
MOV AH,AL ; Save the character to send
rsint_send_loop: ; Loop here until we can send
;; below taken out; ignore cts
;; RESTORE 29 DEC 90 TO WORK WITH UPLOAD/THRUPUT STUFF
MOV DX,CX ; Compute port address for the MSR
ADD DX,msr_8250 ; and then
IN AL,DX ; get it into AX
AND AL,10H ; CTS
jz rsint_send_loop
MOV DX,CX ; Compute port address for the LSR
ADD DX,lsr_8250 ; and then
IN AL,DX ; get itinto AX
and AL,20H ; THR empty?
JZ rsint_send_loop ; No.. Loop back
MOV AL,AH ; Get ready to out character
MOV DX,CX ; Compute port address for the THR
ADD DX,thr_8250 ; and then
OUT DX,AL ; out the character
JMP rsint_status ; Do a status
; Receive a character
rsint_recv:
MOV BX,i_buf_out[BP] ; Get buffer output pointer
rsint_recv_loop:
CMP i_count[BP],0 ; See in anything in buffer
JE rsint_recv_loop ; Wait for it
rsint_get_char:
MOV AL,CS:[BX] ; Get character from buffer
PUSH AX ; Save char
INC BX ; Bump pointer
DEC i_count[BP] ; Dec char count
MOV DX,OFFSET i_buf_e ; Compute end of buffer
ADD DX,BP
CMP BX,DX ; Have we wrapped the buffer?
JL test_handshake ; No.. All done
MOV BX,OFFSET i_buf ; Yes.. Reset pointer
ADD BX,BP
test_handshake:
cmp i_count[BP],80H
jnb test_full
mov ah,flags[BP]
test ah,1 ; Did we RTS off?
jz test_full ; No, so don't RTS on
roll_hands:
mov DX,CX
add DX,mcr_8250
in AL,DX
or AL,00001011B ; Raise DTR, RTS & OUT2
out DX,AL
and AH,0FEH ; Remember RTS is on
mov flags[BP],AH
test_full:
POP AX ; Restore Char
MOV i_buf_out[BP],BX ; Save pointer
MOV AH,last_rs[BP] ; Get last LSR from receive
AND AH,0FEH ; Remove data ready bit
CMP i_count[BP],0 ; Anything left in buffer?
JE short_exit ; Nope so leave
OR AH,1 ; Turn on data ready
short_exit:
JMP rsint_exit ; and go leave
; Status..
rsint_status:
MOV DX,CX ; Compute port address for the LSR
ADD DX,lsr_8250 ; and then
IN AL,DX ; get it
AND AL,0FEH ; Remove data ready bit
CMP i_count[BP],0 ; Anything left in buffer?
JE rsint_status_nodr ; Nope so leave
OR AL,1 ; Turn on data ready
rsint_status_nodr:
MOV AH,AL ; Save LSR
MOV DX,CX ; Compute port address for the MSR
ADD DX,msr_8250 ; and then
IN AL,DX ; get it
JMP rsint_exit ; All done
; Inquiry
; (Return 7388H in AX - Just an identification scheme to tell
; if this silly driver has been loaded)
rsint_inquiry:
MOV AX,07388H
JMP rsint_exit ; and go leave
; 8250 interrupt handler
serint_8250:
PUSH BP
PUSH DX
PUSH AX
PUSH CX ; Save some registers
PUSH DI
xor bp,bp
MOV CX,CS:baseaddr[BP] ; Get base address for chip
MOV DX,CX ; Get the IIR
ADD DX,iir_8250
IN AL,DX
TEST AL,1 ; Interrupt pending?
JZ service
JMP serint_8250_exit ; No leave...
service:
MOV DX,CX ; Get the LSR
ADD DX,lsr_8250
IN AL,DX
MOV last_rs[BP],AL ; And tuck it away
MOV DX,CX ; Get the RBR
ADD DX,rbr_8250
IN AL,DX
MOV DI,i_buf_in[BP] ; Get the buffer pointer
MOV CS:[DI],AL ; Save the character
INC DI ; Bump pointer and handle wrap
MOV AX,OFFSET i_buf_e
ADD AX,BP
CMP DI,AX
JL nowrap
MOV DI,OFFSET i_buf
ADD DI,BP
nowrap:
cmp i_count[BP],buffer_full
jb hand_done
mov DX,CX
add DX,mcr_8250
in al,DX
and AL,11111100B ; Drop DTR & RTS
out DX,AL
mov ah,flags[BP]
or AH,1 ; Remember RTS is off
mov flags[BP],AH
hand_done:
CMP DI,i_buf_out[BP] ; Overflow of buffer?
JNE noover
OR last_rs[BP],2 ; Overrun indicate
JMP SHORT serint_8250_exit ; Don't save the updated pointer
noover:
MOV i_buf_in[BP],DI ; Save the updated pointer
inc i_count[BP] ; inc char count
serint_8250_exit:
MOV AL,20H ; Tell 8259 we are done
OUT pic_cmd_port,AL
POP DI ; Restore registers
POP CX
POP AX
POP DX
POP BP
IRET ; Exit
program_end:
; Main line to initialize.
ASSUME DS: _TEXT
; Constants only needed by initialization
P3F8 DB 0 ;1 IF CARD AT 3F8
P2F8 DB 0 ;1 IF CARD AT 2F8
; INITIALIZE ROUTINE
PUBLIC _COM_START
_COM_START PROC NEAR
PUSH BP
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DS ; save data seg
MOV AX,CS ; Point DS in the right place
MOV DS,AX
;CALL SINON ;PRINT SIGN ON
; MOV DX,00 ;Check to see if support already loaded
; MOV AH,04
; INT 14H
; CMP AX,07388H
; JZ EXIT ;Must be loaded
CALL CNFIG ;CHECK CONFIGURATION
OR AX,AX
JNZ EREXIT ;JMP IF ERRORS
CLI
CALL init_vectors ;SET INTERRUPT VECTORS
STI
POP DS
POP DX
POP CX
POP BX
POP AX
POP BP
ret
;; MOV AL,0 ;set exit code
; MOV DX,OFFSET program_end
; MOV CL,4
; SHR DX,CL
; INC DX
; MOV AH,31H
; INT 21H ; Terminate but stay resident
EREXIT:
LEA DX,LOADERR
MOV AH,9
INT 21H
POP DS
POP DX
POP CX
POP BX
POP AX
POP BP
ret
;MOV AL,1 ;set exit code = Error
; MOV AH,4CH
; INT 21H ; Terminate and return
LOADERR:
DB CR,LF,'COULDNT INSTALL, NO COM DRIVER HERE NOW',CR,LF,'$'
EXIT:
POP DS
POP DX
POP CX
POP BX
POP AX
POP BP
ret
_COM_START ENDP
;---------
CNFIG:
; call to FNDPT, and two lines at CNF1 removed to prevent screw
; up with non-compat machines? done oct 27 88
; CALL FNDPT ;Find Ports
; below 4 ';' inserted 1 april
; CMP P3F8,1
; JNE CNF1
;CNF1: CMP P2F8,1
; JE CNF3
JMP CNF3 ; indicate OK
;CNF2: CMP P3F8,1
; JE CNF3
CNFERR: MOV AX,0FFFFH ;Set Error
RET
CNF3: SUB AX,AX
RET
;------------
FNDPT: MOV DX,03F8H
CALL CKPORT
CMP BP,0
JZ PT2
INC P3F8
PT2: MOV DX,02F8H
CALL CKPORT
CMP BP,0
JZ PT3
INC P2F8
PT3: RET
; Check for valid Port
; Enter with DX containing Port address
; Exit with BP=Port address if port found BP=0 if not found
CKPORT: MOV BP,DX ;For return
MOV CL,DL ;Keep DL Handy
ADD DX,3
IN AL,DX ;Save old LCR in CH
MOV CH,AL
MOV AL,80H ;Address Divisor Latch
OUT DX,AL
CALL WAIT
MOV DL,CL
IN AL,DX
MOV AH,AL ;Save old Divisor
CALL WAIT
INC DX
IN AL,DX ;Save old Divisor
MOV BX,AX
CALL WAIT
MOV DL,CL
MOV AL,55H ;OUTPUT 55
OUT DX,AL
CALL WAIT
INC DX
MOV AL,0AAH
OUT DX,AL ;OUTPUT AA
CALL WAIT
MOV DL,CL
IN AL,DX ;Read New Divisor
MOV AH,AL
CALL WAIT
INC DX
IN AL,DX
CMP AX,55AAH ;DO THEY MATCH?
JZ Match
XOR BP,BP ;Zero - no match
Match: MOV DL,CL
MOV AL,BH ;Restore old Divisor
OUT DX,AL
CALL WAIT
INC DX
MOV AL,BL
OUT DX,AL
CALL WAIT
INC DX
INC DX ;and old LCR
MOV AL,CH
OUT DX,AL
CALL WAIT
WAIT: NOP
RET
; Now snatch the BIOS comm vector (Int 14)
init_vectors:
MOV AL,14H
MOV AH,35H
INT 21H
MOV old_bios_vector,BX ; save old vector
MOV old_bios_vector+2,ES
XOR bp,bp
MOV AL,hiv[bp] ; HG hang onto hdwr vec too
; MOV AL,CS:hiv
MOV AH,35H
INT 21H ; GET OLD HDWR VEC
MOV old_hdwr_vec,BX
MOV old_hdwr_vec+2,ES
;
MOV DX,OFFSET rsint ; Replace with our vector
MOV AL,14H
MOV AH,25H
INT 21H
; Set the hardware interrupt vector
XOR bp,bp ; Get a zero
MOV DX,OFFSET serint_8250 ; Get our address
MOV AL,hiv[BP]
; MOV AL,CS:hiv
MOV AH,25H
INT 21H
; Initialize the buffer ring pointers
MOV AX,OFFSET i_buf ; Get _COM_START of buffer address
ADD AX,BP ; include our offset
MOV i_buf_in[BP],AX ; Put in the buffer pointers
MOV i_buf_out[BP],AX ; Put in the buffer pointers
; Set the interrupt registers in the UART and clean things up
CLI ; Disable interrupts
IN AL,pic_mask_port ; Set up 8259 interupt controller
MOV old_pic_msk , AL ; hang onto it HG
AND AL,int_mask[BP] ; Enable the interrupts for this device
OUT pic_mask_port,AL
MOV CX,baseaddr[BP] ; Get base address for chip
MOV DX,CX ; Compute port address for the IER
ADD DX,ier_8250
IN AL,DX ; current int status
MOV old_ier , AL
MOV AL,1 ; Enable data interrupt only
OUT DX,AL
MOV DX,CX ; Compute port address for the RBR
ADD DX,rbr_8250
IN AL,DX ; Read the input buffer and throw it away
; Enable interrupts
STI ; Enable CPU to receive interupts
RET
PUBLIC _REMOVE_VECTOR
_REMOVE_VECTOR PROC NEAR
assume DS: nothing
;
PUSH BP
PUSH DS
;
;
CLI
;
MOV DX,CS:old_bios_vector ; restore old vector
MOV AX,CS:old_bios_vector+2
MOV DS,AX
;
MOV AL,14H
MOV AH,25H
INT 21H
;
XOR bp,bp
;
;
MOV DX,CS:old_hdwr_vec ; HG replace old hdwr vec
MOV AX,CS:old_hdwr_vec+2
MOV DS,AX
MOV AL,hiv[bp]
; MOV AL,CS:hiv
MOV AH,25H
INT 21H
;
MOV AL,old_pic_msk
OUT pic_mask_port , AL
;
; MOV AL,old_ier
mov al,0 ; disable ints on entire chip
MOV DX,baseaddr[BP]
ADD DX,ier_8250
OUT DX,AL
;
STI
;
POP DS
POP BP
RET
_REMOVE_VECTOR ENDP
if 1
PUBLIC _GETAUX
_GETAUX PROC NEAR
MOV AH,2 ; GET CHAR
MOV DX,COMPORT
INT 14H
XOR AH,AH ; ZAP AH
RET
_GETAUX ENDP
PUBLIC _AUXAVAIL
_AUXAVAIL PROC NEAR
MOV AH,3 ; STAT
MOV DX,COMPORT
INT 14H
AND AX,0100H ; MASK FOR BIT 0 OF AH, DATA READY
RET
_AUXAVAIL ENDP
; PUBLIC _AUXRDY
_AUXRDY PROC NEAR
MOV AH,3 ; STAT
MOV DX,COMPORT
INT 14H
AND AX,0010H ; RETURN CTS STATE
RET
_AUXRDY ENDP
PUBLIC _PUTAUX
_PUTAUX PROC NEAR
PUSH BP
MOV BP,SP
;
MOV AH,1 ; CHAR OUT
MOV DX,COMPORT ; COM2
MOV AL,[BP+4] ; CHAR TO OUTPUT
INT 14H
POP BP
RET
_PUTAUX ENDP
;
;
BUFSIZE EQU 2048 ; SIZE OF BUFFER TO USE FOR READING UPLOAD FILE
;
_DATA SEGMENT 'DATA'
UPHANDLE DW ? ; UPLOAD FILE HANDLE HERE
RBUF DB BUFSIZE DUP (?)
_DATA ENDS
;
;
;
PUBLIC _FILETOTNC
_FILETOTNC PROC NEAR ; UPLOAD A FILE TO THE COM PORT
ASSUME DS:_DATA
PUSH BP
MOV BP,SP
;
MOV DX,[BP+4] ; NEAR STRING POINTER TO FILE NAME
MOV AX,3D00H ; OPEN FILE FOR READ ONLY
INT 21H ; DOS CALL
;
JC ERR ; BRIF ERROR OPENING
;
MOV UPHANDLE,AX ; SAVE FILE HANDLE
;
READBLK:
LEA DX,RBUF ; POINTER TO AREA TO READ TO
MOV CX,BUFSIZE ; READ BUFSIZE CHARS AT A TIME
MOV BX,UPHANDLE
MOV AH,63 ; DOS CALL 63 READ
INT 21H
JC CLERR ; BRIF ERROR READING
TEST AX,AX ; 0 MEANS READ PAST EOF AND WE'RE DONE
JZ OKBYE
;
LEA DI,RBUF
; ELSE AX HAS COUNT OF THIS BLOCK READ, DX POINTS TO BEGINNING OF BLOCK
TOCOMLP:
PUSH AX ; SAVE COUNT
PUSH DI ; AND PTR TO BLOCK
;
MOV AL,BYTE PTR [DI] ; GET A CHAR FROM THE BUFFER
AND AL,07FH
CMP AL,1AH
JE OKBYEPOP ; BRIF ^z ENCOUNTERED = DONE
IF 1 ; IF OUTPUT TO CONSOLE not DESIRED
CMP AL,0AH ; FILTER LINEFEEDS
; JE IGNORE
;
PUSH AX
MOV AH,1 ; CHARACTER OUT
MOV DX,COMPORT
INT 14H ; COM DRIVER CHARACTER OUT CMD
POP AX
ELSE ; else out to console ECHO to console too
MOV AH,14 ; WRITE TTY CHAR
INT 10H ; VIDEO ROM BIOS CALL
ENDIF
;
IGNORE:
CALL SHORT TSTKBD ; CHECK FOR INTERRUPT, RETURN CY SET IF
; ABORT
POP DI
POP AX
;
JC OKBYE ; BRIF ABORT RECEIVED ON KEYBOARD
;
;
INC DI ; BUMP PTR TO NEXT CHAR
DEC AX ; BUMP DOWN
JNZ SHORT TOCOMLP ; IF MORE TO SEND THEN GO FOR IT
JMP SHORT READBLK ; DO NEXT BLOCK
OKBYEPOP:
ADD SP,4 ; FIXUP STACK ON ^z DETECTION AND
; FALL THROUGH TO BYE
;
OKBYE:
XOR AX,AX ; 0 MEANS OKAY
CLERR:
PUSH AX
MOV BX,UPHANDLE ; CLOSE THE OPEN HANDLE
MOV AH,62 ; CLOSE
INT 21H
POP AX
ERR: ; ERR RETURNS WITH ERR CODE
POP BP
RET
_FILETOTNC ENDP
TSTKBD PROC NEAR
MOV AH,1 ; CALL KBD READY SERVICE?
INT 16H
JNZ SHORT GETCH ; BRIF IT WAS READY (NOT Z)
CLC ; INDICATE NOTHING
RET ; BACK TO CALLER
GETCH:
STC ; ELSE SET IT SO now force abort all time
NOTESC: RET ; AND BACK TO CALLER
;
TSTKBD ENDP
; for test - "ping" RTS and DTR lines
PUBLIC _PING_HDWR
_PING_HDWR PROC
MOV DX,3F8H ; Compute port address for the MCR
ADD DX,mcr_8250
mov AL,00001000B ; Lower DTR, RTS, OUT2
out dx,al ; OUT2 turns on interrupts
mov AL,00001011B ; Raise DTR, RTS & OUT2
out dx,al ; OUT2 turns on interrupts
RET
_PING_HDWR ENDP
;Hercules stuff from herc manual
index equ 03b4h
cntrl equ 03b8h
confsw equ 03bfh
scrn_on equ 8
grph equ 2
txt equ 020h
gtable: db 35h,2dh,2eh,07h
db 5bh,02h,57h,57h
db 02,03,00,00
ttable: db 61h,50h,52h,0fh
db 19h,06h,19h,19h
db 02h,0dh,0bh,0ch
PUBLIC _TMODE,_GMODE
assume cs:_TEXT, ds:_TEXT
_GMODE proc near
call enabgr
push es
push ds
;mov ax,xdata
;mov ds,ax
mov ax,cs
mov ds,ax
mov al,grph
lea si,gtable
mov bx,0
mov cx,4000h
call setmd
pop ds
pop es
ret
_GMODE endp
_TMODE proc near
assume cs:_TEXT
call enabgr
push es
push ds
;mov ax,xdata
;mov ds,ax
mov ax,cs
mov ds,ax
mov al,txt
lea si,ttable
mov bx,720h
mov cx,2000H ;shows 2000 (no H) in manual
call setmd
pop ds
pop es
ret
_TMODE endp
enabgr proc near ; merely init to accept graphs
mov dx,confsw ; to software switch
mov al,3 ; allow pg 0 graph
out dx,al
ret
enabgr endp
setmd proc near
assume ds:nothing, cs:_TEXT
push ds
push es
push ax
push bx
push cx
mov dx,cntrl
out dx,al
mov ax,ds
mov es,ax
mov dx,index
mov cx,12
xor ah,ah
parms:
mov al,ah
out dx,al
inc dx
lodsb
out dx,al
inc ah
dec dx
loop parms
pop cx
mov ax,0b000h
cld
mov es,ax
xor di,di
pop ax
rep stosw
;
mov dx,cntrl
pop ax
add al,scrn_on
out dx,al
pop es
pop ds
ret
setmd endp
endif
_TEXT ENDS
END